package com.lzy.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * 日期工具类
 *
 * @author lzy by 2019-09-10
 */

public class DateUtil {

    private static final String TIME_ZONE = "GMT+8:00";

    private final SimpleDateFormat format;

    public DateUtil(SimpleDateFormat format) {
        this.format = format;
    }

    public SimpleDateFormat getFormat() {
        return format;
    }
    /**
     * 紧凑型日期格式，也就是纯数字类型yyyyMMdd
     */
    public static final DateUtil COMPAT = new DateUtil(new SimpleDateFormat("yyyyMMdd"));

    /**
     * 紧凑型日期格式，也就是纯数字类型yyyyMMdd
     */
    public static final DateUtil COMPAT_FULL = new DateUtil(new SimpleDateFormat("yyyyMMddHHmmss"));

    /**
     * 常用日期格式，yyyy-MM-dd
     */
    public static final DateUtil COMMON = new DateUtil(new SimpleDateFormat("yyyy-MM-dd"));
    public static final DateUtil COMMON_FULL = new DateUtil(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    /**
     * 使用斜线分隔的，西方多采用，yyyy/MM/dd
     */
    public static final DateUtil SLASH = new DateUtil(new SimpleDateFormat("yyyy/MM/dd"));

    /**
     * 中文日期格式常用，yyyy年MM月dd日
     */
    public static final DateUtil CHINESE = new DateUtil(new SimpleDateFormat("yyyy年MM月dd日"));
    public static final DateUtil CHINESE_FULL = new DateUtil(new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"));

    /**
     * 日期获取字符串
     */
    public String getDateText(Date date) {
        return getFormat().format(date);
    }

    /**
     * 字符串获取日期
     *
     * @throws ParseException
     */
    public Date getTextDate(String text) throws ParseException {
        return getFormat().parse(text);
    }

    /**
     * 格式化日期
     *
     * @param date 日期
     * @return 格式化后的日期
     */
    public Date formatDate(Date date) {
        try {
            return getFormat().parse(getFormat().format(date));
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 日期获取字符串
     */
    public static String getDateText(Date date, String format) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 字符串获取日期
     *
     * @throws ParseException
     */
    public static Date getTextDate(String dateText, String format) throws ParseException {
        return new SimpleDateFormat(format).parse(dateText);
    }

    /**
     * 根据日期，返回其星期数，周一为1，周日为7
     *
     * @param date
     * @return
     */
    public static int getWeekDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int w = calendar.get(Calendar.DAY_OF_WEEK);
        int ret;
        if (w == Calendar.SUNDAY) {
            ret = 7;
        } else {
            ret = w - 1;
        }
        return ret;
    }

    public static int getAge(Date birthday) {
        Calendar calendar = Calendar.getInstance();
        if (calendar.before(birthday)) {
            throw new IllegalArgumentException("出生时间大于当前时间!");
        }
        int yearNow = calendar.get(Calendar.YEAR);
        int monthNow = calendar.get(Calendar.MONTH) + 1;// 注意此处，如果不加1的话计算结果是错误的
        int dayOfMonthNow = calendar.get(Calendar.DAY_OF_MONTH);
        calendar.setTime(birthday);
        int yearBirth = calendar.get(Calendar.YEAR);
        int monthBirth = calendar.get(Calendar.MONTH);
        int dayOfMonthBirth = calendar.get(Calendar.DAY_OF_MONTH);
        int age = yearNow - yearBirth;
        if (monthNow < monthBirth || (monthNow == monthBirth && dayOfMonthNow < dayOfMonthBirth)) {
            age--;
        }
        return age;

    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param smdate 较小的时间
     * @param bdate  较大的时间
     * @return 相差天数
     */
    public static int daysBetween(Date smdate, Date bdate) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(smdate);
        long time1 = cal.getTimeInMillis();
        cal.setTime(bdate);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 获取指定时间的当月第一天时间
     *
     * @param date 时间
     * @return 当月1号时间
     * 调用方式，如yyyy-MM-dd格式：DateUtil.COMMON.getCurMonFirstDayForDate(new Date())
     */
    public Date getCurMonFirstDayForDate(Date date) {
        Calendar cl = Calendar.getInstance();
        try {
            cl.setTime(getTextDate(getDateText(date)));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cl.set(Calendar.DATE, 1);
        return cl.getTime();
    }

    /**
     * 获取指定时间的下月第一天时间
     *
     * @param date 时间
     * @return 下月1号时间
     * 调用方式，如yyyy-MM-dd格式：DateUtil.COMMON.getNextMonFirstDayForDate(new Date())
     */
    public Date getNextMonFirstDayForDate(Date date) {
        Calendar cl = Calendar.getInstance();
        try {
            cl.setTime(getTextDate(getDateText(date)));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cl.add(Calendar.MONTH, 1);
        cl.set(Calendar.DATE, 1);
        return cl.getTime();
    }

    /**
     * 获取指定时间的上月第一天时间
     *
     * @param date 时间
     * @return 上月1号时间
     * 调用方式，如yyyy-MM-dd格式：DateUtil.COMMON.getPreviousMonFirstDayForDate(new Date())
     */
    public Date getPreviousMonFirstDayForDate(Date date) {
        Calendar cl = Calendar.getInstance();
        try {
            cl.setTime(getTextDate(getDateText(date)));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cl.add(Calendar.MONTH, -1);
        cl.set(Calendar.DATE, 1);
        return cl.getTime();
    }

    /**
     * 获取指定时间的当年第一天时间
     *
     * @param date 时间
     * @return 当年1号时间
     * 调用方式，如yyyy-MM-dd格式：DateUtil.COMMON.getCurYearFirstDayForDate(new Date())
     */
    public Date getCurYearFirstDayForDate(Date date) {
        Calendar cl = Calendar.getInstance();
        try {
            cl.setTime(getTextDate(getDateText(date)));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cl.set(Calendar.MONTH, 0);
        cl.set(Calendar.DATE, 1);
        return cl.getTime();
    }

    /**
     * 获取指定时间的年份
     *
     * @param date
     * @return 年
     */
    public static int getYear(Date date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(date);
        return cl.get(Calendar.YEAR);
    }

    /**
     * 获取指定时间的月份
     *
     * @param date
     * @return 月
     */
    public static int getMonth(Date date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(date);
        return cl.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取指定时间的日期
     *
     * @param date 时间对象
     * @return 日
     */
    public static int getDate(Date date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(date);
        return cl.get(Calendar.DATE);
    }

    /**
     * 获取指定时间的当月里所有天的日期
     *
     * @param date
     * @return 所有天的数组
     */
    public static Date[] getCurMonthAllDaysToDate(Date date) {
        Calendar cl = Calendar.getInstance();
        cl.setTime(date);
        int maxDay = cl.getActualMaximum(Calendar.DATE);
        Date[] dateArray = new Date[maxDay];
        for (int i = 1; i <= maxDay; i++) {
            cl.set(Calendar.DATE, i);
            dateArray[i - 1] = cl.getTime();
        }
        return dateArray;
    }

    /**
     * 两个时间相差距离多少天多少小时多少分多少秒
     *
     * @param str1 时间参数 1 格式：1990-01-01 12:00:00
     * @param str2 时间参数 2 格式：2009-01-01 12:00:00
     * @return long[] 返回值为：{天, 时, 分, 秒}
     */
    public static long[] getDistanceTimes(String str1, String str2) {
        Date one;
        Date two;
        long day = 0;
        long hour = 0;
        long min = 0;
        long sec = 0;
        try {
            one = COMMON_FULL.getTextDate(str1);
            two = COMMON_FULL.getTextDate(str2);
            long time1 = one.getTime();
            long time2 = two.getTime();
            long diff;
            if (time1 < time2) {
                diff = time2 - time1;
            } else {
                diff = time1 - time2;
            }
            day = diff / (24 * 60 * 60 * 1000);
            hour = diff / (60 * 60 * 1000);
            min = diff / (60 * 1000);
            sec = diff / 1000;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        long[] times = {day, hour, min, sec};
        return times;
    }

    //获取当前系统下一天日期
    public static Date getNextDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, +1);
        date = calendar.getTime();
        return date;
    }

    //获取当前系统下n天日期
    public static Date getNexNtDay(Date date, Integer n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, +n);
        date = calendar.getTime();
        return date;
    }

    /**
     * 秒转换为指定格式的日期
     *
     * @param second
     * @return
     */
    public static Date secondToDate(long second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(second * 1000);
        return calendar.getTime();
    }

    /**
     * 获取指定某一天的开始时间戳
     *
     * @param timeStamp 毫秒级时间戳
     * @return
     */
    public static Long getDailyStartTime(Long timeStamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
        calendar.setTimeInMillis(timeStamp);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis();
    }

    /**
     * 获取指定某一天的结束时间戳
     *
     * @param timeStamp 毫秒级时间戳
     * @return
     */
    public static Long getDailyEndTime(Long timeStamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
        calendar.setTimeInMillis(timeStamp);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTimeInMillis();
    }
}